#include <glf/core/inlines.h>
#include <errno.h>

namespace glf {

#ifndef NULL
#define NULL 0
#endif

#ifndef GLF_HAS_STRLEN

size_t Strlen(const char* str) {
    size_t length = 0;
    while(*str++) {
        ++length;
    }
    return length;
}

#define GLF_HAS_STRLEN
#endif

#ifndef GLF_HAS_TOUPPER
int toupper(int s) {
    if(('a' <= s) && (s <= 'z'))
        return 'A' + (s - 'a');
    else
        return s;
}
#define GLF_HAS_TOUPPER
#endif


#ifndef GLF_HAS_SNPRINTF
int Snprintf(char *str, size_t N, const char *format, ...)
{
	glfVaList args;
	glfVaStart(args, format);
	
	int value = Vsnprintf(str, N, format, args);

	glfVaEnd(args);

	return value;
}
#define GLF_HAS_SNPRINTF
#endif

#ifndef GLF_HAS_VSNPRINTF

int Vsnprintf(char *str, size_t count, const char *fmt, glfVaList arg);

static int dopr (char *buffer, size_t maxlen, const char *format, glfVaList args);
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, const char *value, int flags, int min, int max);
static int fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, unsigned int max, int flags);
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, double fvalue, int min, int max, int flags);
static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );

/*
* dopr(): poor man's version of doprintf
*/

/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS   1
#define DP_S_MIN     2
#define DP_S_DOT     3
#define DP_S_MAX     4
#define DP_S_MOD     5
#define DP_S_MOD_L   6
#define DP_S_CONV    7
#define DP_S_DONE    8

/* format flags - Bits */
#define DP_F_MINUS 	(1 << 0)
#define DP_F_PLUS  	(1 << 1)
#define DP_F_SPACE 	(1 << 2)
#define DP_F_NUM   	(1 << 3)
#define DP_F_ZERO  	(1 << 4)
#define DP_F_UP    	(1 << 5)
#define DP_F_UNSIGNED 	(1 << 6)

/* Conversion Flags */
#define DP_C_SHORT   1
#define DP_C_LONG    2
#define DP_C_long   3
#define DP_C_double 4

#define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q)
#define MIN(p,q) ((p <= q) ? p : q)

typedef unsigned int uint32;

static int dopr (char *buffer, size_t maxlen, const char *format, glfVaList args)
{
    char ch;
    long value;
    double fvalue;
    char *strvalue;
    int min;
    uint32 max;
    int state;
    int flags;
    int cflags;
    int total;
    size_t currlen;

    state = DP_S_DEFAULT;
    currlen = flags = cflags = min = 0;
    max = uint32(-1);
    ch = *format++;
    total = 0;

    while (state != DP_S_DONE)
    {
        if (ch == '\0')
            state = DP_S_DONE;

        switch(state) 
        {
        case DP_S_DEFAULT:
            if (ch == '%') 
                state = DP_S_FLAGS;
            else 
                total += dopr_outch (buffer, &currlen, maxlen, ch);
            ch = *format++;
            break;
        case DP_S_FLAGS:
            switch (ch) 
            {
            case '-':
                flags |= DP_F_MINUS;
                ch = *format++;
                break;
            case '+':
                flags |= DP_F_PLUS;
                ch = *format++;
                break;
            case ' ':
                flags |= DP_F_SPACE;
                ch = *format++;
                break;
            case '#':
                flags |= DP_F_NUM;
                ch = *format++;
                break;
            case '0':
                flags |= DP_F_ZERO;
                ch = *format++;
                break;
            default:
                state = DP_S_MIN;
                break;
            }
            break;
        case DP_S_MIN:
            if ('0' <= ch && ch <= '9')
            {
                min = 10*min + char_to_int (ch);
                ch = *format++;
            } 
            else if (ch == '*') 
            {
                min = glfVaArg (args, int);
                ch = *format++;
                state = DP_S_DOT;
            } 
            else 
                state = DP_S_DOT;
            break;
        case DP_S_DOT:
            if (ch == '.') 
            {
                state = DP_S_MAX;
                ch = *format++;
            } 
            else 
                state = DP_S_MOD;
            break;
        case DP_S_MAX:
            if ('0' <= ch && ch <= '9')
            {
                //if (max < 0) // Max is unsigned, comparison is pointless...
                //    max = 0;
                max = 10*max + char_to_int (ch);
                ch = *format++;
            } 
            else if (ch == '*') 
            {
                max = glfVaArg (args, int);
                ch = *format++;
                state = DP_S_MOD;
            } 
            else 
                state = DP_S_MOD;
            break;
        case DP_S_MOD:
            switch (ch) 
            {
            case 'h':
                cflags = DP_C_SHORT;
                ch = *format++;
                break;
            case 'l':
                cflags = DP_C_LONG;
                ch = *format++;
                break;
            case 'L':
                cflags = DP_C_double;
                ch = *format++;
                break;
            default:
                break;
            }
            if (cflags != DP_C_LONG)
                state = DP_S_CONV;
            else
                state = DP_S_MOD_L;
            break;
        case DP_S_MOD_L:
            switch (ch)
            {
            case 'l':
                cflags = DP_C_long;
                ch = *format++;
                break;
            default:
                break;
            }
            state = DP_S_CONV;
            break;
        case DP_S_CONV:
            switch (ch) 
            {
            case 'd':
            case 'i':
                if (cflags == DP_C_SHORT) 
                    value = (short int)glfVaArg (args, int);
                else if (cflags == DP_C_LONG)
                    value = glfVaArg (args, long int);
                else if (cflags == DP_C_long)
                    value = glfVaArg (args, long);
                else
                    value = glfVaArg (args, int);
                total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
                break;
            case 'o':
                flags |= DP_F_UNSIGNED;
                if (cflags == DP_C_SHORT)
                    value = (unsigned short int)glfVaArg (args, unsigned int);
                else if (cflags == DP_C_LONG)
                    value = glfVaArg (args, unsigned long int);
                else if (cflags == DP_C_long)
                    value = glfVaArg (args, unsigned long);
                else
                    value = glfVaArg (args, unsigned int);
                total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
                break;
            case 'u':
                flags |= DP_F_UNSIGNED;
                if (cflags == DP_C_SHORT)
                    value = (unsigned short int)glfVaArg (args, unsigned int);
                else if (cflags == DP_C_LONG)
                    value = glfVaArg (args, unsigned long int);
                else if (cflags == DP_C_long)
                    value = glfVaArg (args, unsigned long);
                else
                    value = glfVaArg (args, unsigned int);
                total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
                break;
            case 'X':
                flags |= DP_F_UP;
            case 'x':
                flags |= DP_F_UNSIGNED;
                if (cflags == DP_C_SHORT)
                    value = (unsigned short int)glfVaArg (args, unsigned int);
                else if (cflags == DP_C_LONG)
                    value = glfVaArg (args, unsigned long int);
                else if (cflags == DP_C_long)
                    value = glfVaArg (args, unsigned long);
                else
                    value = glfVaArg (args, unsigned int);
                total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
                break;
            case 'f':
                if (cflags == DP_C_double)
                    fvalue = glfVaArg (args, double);
                else
                    fvalue = glfVaArg (args, double);
                /* um, floating point? */
                total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
                break;
            case 'E':
                flags |= DP_F_UP;
            case 'e':
                if (cflags == DP_C_double)
                    fvalue = glfVaArg (args, double);
                else
                    fvalue = glfVaArg (args, double);
                /* um, floating point? */
                total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
                break;
            case 'G':
                flags |= DP_F_UP;
            case 'g':
                if (cflags == DP_C_double)
                    fvalue = glfVaArg (args, double);
                else
                    fvalue = glfVaArg (args, double);
                /* um, floating point? */
                total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
                break;
            case 'c':
                total += dopr_outch (buffer, &currlen, maxlen, glfVaArg (args, int));
                break;
            case 's':
                strvalue = glfVaArg (args, char *);
                total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
                break;
            case 'p':
                strvalue = glfVaArg (args, char *);
                total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
                    max, flags);
                break;
            case 'n':
                if (cflags == DP_C_SHORT) 
                {
                    short int *num;
                    num = glfVaArg (args, short int *);
                    *num = currlen;
                }
                else if (cflags == DP_C_LONG) 
                {
                    long int *num;
                    num = glfVaArg (args, long int *);
                    *num = currlen;
                } 
                else if (cflags == DP_C_long) 
                {
                    long *num;
                    num = glfVaArg (args, long *);
                    *num = currlen;
                } 
                else 
                {
                    int *num;
                    num = glfVaArg (args, int *);
                    *num = currlen;
                }
                break;
            case '%':
                total += dopr_outch (buffer, &currlen, maxlen, ch);
                break;
            case 'w':
                /* not supported yet, treat as next char */
                ch = *format++;
                break;
            default:
                /* Unknown, skip */
                break;
            }
            ch = *format++;
            state = DP_S_DEFAULT;
            flags = cflags = min = 0;
            max = uint32(-1);
            break;
        case DP_S_DONE:
            break;
        default:
            /* hmm? */
            break; /* some picky compilers need this */
        }
    }
    if (buffer != NULL)
    {
        if (currlen < maxlen - 1) 
            buffer[currlen] = '\0';
        else 
            buffer[maxlen - 1] = '\0';
    }
    return total;
}

static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
    const char *value, int flags, int min, int max)
{
    int padlen, strln;     /* amount to pad */
    int cnt = 0;
    int total = 0;

    if (value == 0)
    {
        value = "<NULL>";
    }

    for (strln = 0; value[strln]; ++strln); /* strlen */
    if (max >= 0 && max < strln)
        strln = max;
    padlen = min - strln;
    if (padlen < 0) 
        padlen = 0;
    if (flags & DP_F_MINUS) 
        padlen = -padlen; /* Left Justify */

    while (padlen > 0)
    {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        --padlen;
    }
    while (*value && ((max < 0) || (cnt < max)))
    {
        total += dopr_outch (buffer, currlen, maxlen, *value++);
        ++cnt;
    }
    while (padlen < 0)
    {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        ++padlen;
    }
    return total;
}

/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */

static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
    long value, int base, int min, unsigned int max, int flags)
{
    int signvalue = 0;
    unsigned long uvalue;
    char convert[24];
    unsigned int place = 0;
    int spadlen = 0; /* amount to space pad */
    int zpadlen = 0; /* amount to zero pad */
    const char *digits;
    int total = 0;

    //if (max < 0) // Max is unsigned, comparison is pointless...
    //    max = 0;

    uvalue = value;

    if(!(flags & DP_F_UNSIGNED))
    {
        if( value < 0 ) {
            signvalue = '-';
            uvalue = -value;
        }
        else
            if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
                signvalue = '+';
            else
                if (flags & DP_F_SPACE)
                    signvalue = ' ';
    }

    if (flags & DP_F_UP)
        /* Should characters be upper case? */
        digits = "0123456789ABCDEF";
    else
        digits = "0123456789abcdef";

    do {
        convert[place++] = digits[uvalue % (unsigned)base];
        uvalue = (uvalue / (unsigned)base );
    } while(uvalue && (place < sizeof (convert)));
    if (place == sizeof (convert)) place--;
    convert[place] = 0;

    zpadlen = max - place;
    spadlen = min - MAX(max, place) - (signvalue ? 1 : 0) - 1;
    if (zpadlen < 0) zpadlen = 0;
    if (spadlen < 0) spadlen = 0;
    if (flags & DP_F_ZERO)
    {
        zpadlen = MAX(zpadlen, spadlen);
        spadlen = 0;
    }
    if (flags & DP_F_MINUS) 
        spadlen = -spadlen; /* Left Justifty */

    /* Spaces */
    while (spadlen > 0) 
    {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        --spadlen;
    }

    /* Sign */
    if (signvalue) 
        total += dopr_outch (buffer, currlen, maxlen, signvalue);

    /* Zeros */
    if (zpadlen > 0) 
    {
        while (zpadlen > 0)
        {
            total += dopr_outch (buffer, currlen, maxlen, '0');
            --zpadlen;
        }
    }

    /* Digits */
    while (place > 0) 
        total += dopr_outch (buffer, currlen, maxlen, convert[--place]);

    /* Left Justified spaces */
    while (spadlen < 0) {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        ++spadlen;
    }

    return total;
}

static double abs_val (double value)
{
    double result = value;

    if (value < 0)
        result = -value;

    return result;
}

static int pow10 (int exp)
{
    int result = 1;

    while (exp)
    {
        result *= 10;
        exp--;
    }

    return result;
}
/*
static double pow10 (double exp)
{
double result = 1;

while (exp)
{
result *= 10;
exp--;
}

return result;
}
*/
static long round(double value)
{
    long intpart = static_cast<long>(value);

    value = value - intpart;

    if (value >= 0.5)
        intpart++;

    return intpart;
}

static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, double fvalue, int min, int max, int flags)
{
    int signvalue = 0;
    double ufvalue;
    char iconvert[20];
    char fconvert[20];
    int iplace = 0;
    int fplace = 0;
    int padlen = 0; /* amount to pad */
    int zpadlen = 0; 
    int caps = 0;
    int total = 0;
    long intpart;
    long fracpart;

    /* 
    * AIX manpage says the default is 0, but Solaris says the default
    * is 6, and sprintf on AIX defaults to 6
    */
    if (max < 0)
        max = 6;

    ufvalue = abs_val (fvalue);

    if (fvalue < 0)
        signvalue = '-';
    else
        if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
            signvalue = '+';
        else
            if (flags & DP_F_SPACE)
                signvalue = ' ';

    intpart = static_cast<long>(ufvalue);

    /* 
    * Sorry, we only support 9 digits past the decimal because of our 
    * conversion method
    */
    if (max > 9)
        max = 9;

    /* We "cheat" by converting the fractional part to integer by
    * multiplying by a factor of 10
    */
    fracpart = round ((pow10 (max)) * (ufvalue - intpart));

    if (fracpart >= pow10 (max))
    {
        intpart++;
        fracpart -= pow10 (max);
    }

    /* Convert integer part */
    do {
        iconvert[iplace++] =
            (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
        intpart = (intpart / 10);
    } while(intpart && (iplace < 20));
    if (iplace == 20) iplace--;
    iconvert[iplace] = 0;

    /* Convert fractional part */
    do {
        fconvert[fplace++] =
            (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
        fracpart = (fracpart / 10);
    } while(fracpart && (fplace < 20));
    if (fplace == 20) fplace--;
    fconvert[fplace] = 0;

    /* -1 for decimal point, another -1 if we are printing a sign */
    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
    zpadlen = max - fplace;
    if (zpadlen < 0)
        zpadlen = 0;
    if (padlen < 0) 
        padlen = 0;
    if (flags & DP_F_MINUS) 
        padlen = -padlen; /* Left Justifty */

    if ((flags & DP_F_ZERO) && (padlen > 0)) 
    {
        if (signvalue) 
        {
            total += dopr_outch (buffer, currlen, maxlen, signvalue);
            --padlen;
            signvalue = 0;
        }
        while (padlen > 0)
        {
            total += dopr_outch (buffer, currlen, maxlen, '0');
            --padlen;
        }
    }
    while (padlen > 0)
    {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        --padlen;
    }
    if (signvalue) 
        total += dopr_outch (buffer, currlen, maxlen, signvalue);

    while (iplace > 0) 
        total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);

    /*
    * Decimal point.  This should probably use locale to find the correct
    * char to print out.
    */
    if (max > 0)
    {
        total += dopr_outch (buffer, currlen, maxlen, '.');

        while (zpadlen-- > 0)
            total += dopr_outch (buffer, currlen, maxlen, '0');

        while (fplace > 0) 
            total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
    }

    while (padlen < 0) 
    {
        total += dopr_outch (buffer, currlen, maxlen, ' ');
        ++padlen;
    }

    return total;
}

static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
{
    if (*currlen + 1 < maxlen)
        buffer[(*currlen)++] = c;
    return 1;
}

#ifndef GLF_HAS_STRSTR
char *Strstr(char * string1, char * string2)
{

    char *start, *p1, *p2;
    for(start = &string1[0]; *start != '\0'; start++)
    {        /* for each position in input string... */
        p1 = string2;    /* prepare to check for pattern string there */
        p2 = start;
        while(*p1 != '\0')
        {
            if(*p1 != *p2)    /* characters differ */
                break;
            p1++;
            p2++;
        }
        if(*p1 == '\0')        /* found match */
            return start;
    }

    return 0;

}
#define GLF_HAS_STRSTR
#endif

#ifndef GLF_HAS_STRSTR_CONST
const char *Strstr(const char * string1, const char * string2)
{

    const char *start, *p1, *p2;
    for(start = &string1[0]; *start != '\0'; start++)
    {        /* for each position in input string... */
        p1 = string2;    /* prepare to check for pattern string there */
        p2 = start;
        while(*p1 != '\0')
        {
            if(*p1 != *p2)    /* characters differ */
                break;
            p1++;
            p2++;
        }
        if(*p1 == '\0')        /* found match */
            return start;
    }

    return 0;

}
#define GLF_HAS_STRSTR_CONST
#endif

#ifndef GLF_HAS_STRRCHR
char * Strrchr (char * s, int c) {
    char *rtnval = 0;
    do {
        if (*s == c)
            rtnval = (char*) s;
    } while (*s++);
    return (rtnval);
}

#define GLF_HAS_STRRCHR
#endif

#ifndef GLF_HAS_STRRCHR_CONST
const char * Strrchr (const char * s, int c) {
    const char *rtnval = 0;
    do {
        if (*s == c)
            rtnval = (char*) s;
    } while (*s++);
    return (rtnval);
}
#define GLF_HAS_STRRCHR_CONST
#endif

int Vsnprintf (char *str, size_t count, const char *fmt, glfVaList args)
{
    if (str != NULL)
        str[0] = 0;
    return dopr(str, count, fmt, args);
}
#define GLF_HAS_VSNPRINTF
#endif //GLF_HAS_VSNPRINTF

#ifndef GLF_HAS_VSPRINTF_S
int Vsprintf_s(char* str, size_t N, const char* format, glfVaList args) {
    return Vsnprintf(str, N, format, args);
}
#define GLF_HAS_VSPRINTF_S
#endif

#ifndef GLF_HAS_VSNPRINTF_S
int Vsnprintf_s(char* str, size_t N, size_t maxWrite, const char* format, glfVaList args) {
    int end = Vsprintf_s(str, N, format, args);

    end = Min(end, static_cast<int>(maxWrite));

    str[end] = 0;

    return end;
}
#define GLF_HAS_VSNPRINTF_S
#endif

#ifndef GLF_HAS_STRNLEN_S
size_t Strnlen_s(const char* str, size_t N) {
    for(size_t i = 0; i < N; i++) {
        if(*str++ == 0) {
            return i + 1;
        }
    }
    return N;
}
#define GLF_HAS_STRNLEN_S
#endif

#ifndef GLF_HAS_STRCHR_CONST
const char* Strchr(const char * str, int ch) {
    while(*str++) {
        if(*str == ch) {
            return str;
        }
    }
    return 0;
}
#define GLF_HAS_STRNLEN_S
#endif

#ifndef GLF_HAS_STRCPY_S
int Strcpy_s(char* dst, size_t dst_max, const char* src) {
    if ((dst_max == 0) || (dst == NULL) || (src == NULL) ) //|| (dst_max > RSIZE_MAX)
    {
        //__msl_runtime_constraint_violation_s(NULL, NULL, ERANGE);
        return ERANGE;
    }

    if(dst_max <= Strnlen_s(src, dst_max))
    {
        //__msl_runtime_constraint_violation_s(NULL, NULL, ERANGE);
        dst[0] = 0;
        return ERANGE;
    }

    Strcpy(dst, src);
    return 0;
}
#define GLF_HAS_STRCPY_S
#endif

#ifndef GLF_HAS_STRCPY
char* Strcpy(char* dst, const char* src) {
    int retval = Strcpy_s(dst, Strlen(src), src);
    if(!retval) {
        return dst;
    }
    return 0;
}
#define GLF_HAS_STRCPY
#endif

#ifndef GLF_HAS_STRCMP
int Strcmp(const char* str1, const char* str2) {
    while (1)
    {
        char c1 = *str1++;
        char c2 = *str2++;
        if (c1 < c2) return -1;
        if (c1 > c2) return 1;
        if (c1 == 0) return 0;
    }
    return 1;
}
#define GLF_HAS_STRCMP
#endif

#ifndef GLF_HAS_STRNCMP
int Strncmp(const char* str1, const char* str2, size_t num) {
    for(size_t i = 0; i < num; i++)
    {
        char c1 = *str1++;
        char c2 = *str2++;
        if (c1 == 0 && c2 == 0) return 0;
        if (c1 == 0 || c1 < c2) return -1;
        if (c2 == 0 || c1 > c2) return 1;
    }
    return 0;
}
#define GLF_HAS_STRNCMP
#endif

#ifndef GLF_HAS_STRNCPY_S
errno_t Strncpy_s(char* dst, size_t maxDst, const char* src, size_t count) {
    if(count > maxDst || dst == 0 || src == 0) {
        return 1;
    }
    int i = 0;
    for(; i < count; i++) {
        if(*src == 0) {
            break;
        }
        *dst++ = *src++;
    }
    if(i < maxDst) {
        *dst = 0;
    }
    return 0;
}
#define GLF_HAS_STRNCPY_S
#endif

#ifndef GLF_HAS_STRICMP
int Stricmp(const char* str1, const char* str2) {
    while (1)
    {
        char c1 = toupper(*str1++);
        char c2 = toupper(*str2++);
        if (c1 < c2) return -1;
        if (c1 > c2) return 1;
        if (c1 == 0) return 0;
    }
}
#define GLF_HAS_STRICMP
#endif

#ifndef GLF_HAS_STRNICMP
int Strnicmp(const char* str1, const char* str2, size_t num) {
    for (size_t i = 0; i < num; i++)
    {
        char c1 = toupper(*str1++);
        char c2 = toupper(*str2++);
        if (c1 < c2) return -1;
        if (c1 > c2) return 1;
        if (!c1) return 0;
    }
    return 0;
}
#define GLF_HAS_STRNICMP

#endif

#ifndef GLF_HAS_STRCAT_S

//untested !
errno_t Strcat_s(char* dst, size_t N, const char* src) {
    size_t count = 0;

    while(*dst && count < N) {
        ++dst;
        ++count;
    }

    while(*src && count < N) {
        *dst++ = *src++;
        ++count;
    }

    *dst = 0;

    if(count < N) {
        return 0;
    } else {
        //TODO[dc]: should return something else !!
        return 1; 
    }
}
#define GLF_HAS_STRCAT_S

#endif

#ifndef GLF_HAS_WCSICMP
int Wcsicmp(const wchar_t* str1, const wchar_t* str2) {
    while(true)
    {
        wchar_t c1 = toupper(*str1++);
        wchar_t c2 = toupper(*str2++);

        if (c1 < c2) return -1;
        if (c1 > c2) return 1;
        if (c1 == 0) return 0;
    }
}
#define GLF_HAS_WCSICMP
#endif


} //namespace glf
